
/******************************************************************************
 * MODULE     : misc.cpp
 * DESCRIPTION: Decoration boxes (mostly for use on the screen)
 * COPYRIGHT  : (C) 1999  Joris van der Hoeven
 *******************************************************************************
 * This software falls under the GNU general public license version 3 or later.
 * It comes WITHOUT ANY WARRANTY WHATSOEVER. For details, see the file LICENSE
 * in the root directory or <http://www.gnu.org/licenses/gpl-3.0.html>.
 ******************************************************************************/

#include "Boxes/composite.hpp"
#include "Boxes/construct.hpp"
#include "observers.hpp"
#include "scheme.hpp"

bool in_presentation_mode ();

/******************************************************************************
 * Specific boxes
 ******************************************************************************/

struct specific_box_rep : public box_rep {
  box    b;
  string filter;
  specific_box_rep (path ip, box b2, string filter2, font fn, bool keep_size)
      : box_rep (ip), b (b2), filter (filter2) {
    if (keep_size) {
      x1= b->x1;
      y1= b->y1;
      x2= b->x2;
      y2= b->y2;
    }
    else {
      x1= x2= y1= 0;
      y2        = fn->yx;
    }
    x3= b->x3;
    y3= b->y3;
    x4= b->x4;
    y4= b->y4;
  }
  operator tree () { return tuple ("specific", (tree) b, filter); }
  void display (renderer ren) {
    bool ok= false;
    if (filter == "screen") ok= !ren->is_printer () && !in_presentation_mode ();
    else if (filter == "printer") ok= ren->is_printer ();
    else if (filter == "even") ok= (ren->cur_page & 1) == 0;
    else if (filter == "odd") ok= (ren->cur_page & 1) == 1;
    if (ok) {
      rectangles rs;
      b->redraw (ren, path (), rs);
    }
  }
};

/******************************************************************************
 * TOC boxes
 ******************************************************************************/

struct toc_box_rep : public box_rep {
  string kind, title;
  toc_box_rep (path ip, string kind2, string title2, font fn)
      : box_rep (ip), kind (kind2), title (title2) {
    x1= x2= y1= 0;
    y2        = fn->yx;
    x3= x4= y3= y4= 0;
  }
  operator tree () { return tuple ("toc", kind, title); }
  void display (renderer ren) { ren->toc_entry (kind, title, 0, y2); }
};

/******************************************************************************
 * Flag boxes
 ******************************************************************************/

struct flag_box_rep : public composite_box_rep {
  brush light;
  brush old_bg;
  flag_box_rep (path ip, box b, SI h, pencil dark, brush light);
  operator tree () { return tree (TUPLE, "flag"); }
  void pre_display (renderer& ren);
  void post_display (renderer& ren);
};

void
flag_box_rep::pre_display (renderer& ren) {
  old_bg= ren->get_background ();
  ren->set_background (light);
}

void
flag_box_rep::post_display (renderer& ren) {
  ren->set_background (old_bg);
}

flag_box_rep::flag_box_rep (path ip, box b, SI h, pencil dark, brush light2)
    : composite_box_rep (ip), light (light2) {
  SI        sep= h / 5, H= b->h () + 2 * sep, w= b->w () + 2 * sep, W= H / 4;
  path      dip= decorate_middle (ip);
  array<SI> x (5), y (5);
  x[0]= 0;
  y[0]= 0;
  x[1]= w;
  y[1]= 0;
  x[2]= w + W;
  y[2]= H / 2;
  x[3]= w;
  y[3]= H;
  x[4]= 0;
  y[4]= H;
  insert (line_box (dip, 0, 0, 0, h, dark), 0, 0);
  insert (polygon_box (dip, x, y, light, dark), 0, h);
  insert (b, sep - b->x1, h + sep - b->y1);
  position ();
  finalize ();
}

/******************************************************************************
 * Info boxes
 ******************************************************************************/

struct info_box_rep : public composite_box_rep {
  info_box_rep (path ip, SI h, pencil dark, brush light);
  operator tree () { return tree (TUPLE, "info"); }
};

info_box_rep::info_box_rep (path ip, SI h, pencil dark, brush light)
    : composite_box_rep (ip) {
  SI        d  = h / 5;
  path      dip= decorate_middle (ip);
  array<SI> x (4), y (4);
  x[0]= 0;
  y[0]= -d;
  x[1]= d;
  y[1]= 0;
  x[2]= 0;
  y[2]= d;
  x[3]= -d;
  y[3]= 0;
  insert (line_box (dip, 0, 0, 0, h - d, dark), 0, 0);
  insert (polygon_box (dip, x, y, light, dark), 0, h);
  position ();
  finalize ();
}

/******************************************************************************
 * Scrollbar boxes
 ******************************************************************************/

struct scrollbar_box_rep : public composite_box_rep {
  bool vertical;
  SI   span;
  tree t;
  scrollbar_box_rep (path ip, box b, bool vertical2, SI span2, tree t2)
      : composite_box_rep (ip), vertical (vertical2), span (span2), t (t2) {
    insert (b, 0, 0);
    position ();
    finalize ();
  }
  operator tree () { return tuple ("scrollbar", (tree) bs[0]); }
  tree message (tree type, SI x, SI y, rectangles& rs);
};

tree
scrollbar_box_rep::message (tree type, SI x, SI y, rectangles& rs) {
  (void) rs;
  if (type != "click" && type != "drag") return "";
  tree u= t;
  if (vertical) {
    double p = 100.0;
    SI     Y1= y1 + (span >> 1);
    SI     Y2= y2 - (span >> 1);
    if (Y1 < Y2) p= 100.0 * ((double) (y - Y1)) / ((double) (Y2 - Y1));
    p= min (100.0, max (0.0, p));
    u= tree (as_string (p) * "%");
  }
  else {
    double p = 0.0;
    SI     X1= x1 + (span >> 1);
    SI     X2= x2 - (span >> 1);
    if (X1 < X2) p= 100.0 * ((double) (x - X1)) / ((double) (X2 - X1));
    p= max (0.0, min (100.0, p));
    u= tree (as_string (p) * "%");
  }
  if (u != t && is_accessible (obtain_ip (t))) {
    object fun= symbol_object ("tree-set");
    object cmd= list_object (fun, t, u);
    exec_delayed (scheme_cmd (cmd));
  }
  return "done";
}

/******************************************************************************
 * box construction routines
 ******************************************************************************/

box
specific_box (path ip, box b, string filter, font fn, bool keep_size) {
  return tm_new<specific_box_rep> (ip, b, filter, fn, keep_size);
}

box
toc_box (path ip, string kind, string title, font fn) {
  return tm_new<toc_box_rep> (ip, kind, title, fn);
}

box
flag_box (path ip, box b, SI h, pencil dark, brush light) {
  return tm_new<flag_box_rep> (ip, b, h, dark, light);
}

box
info_box (path ip, SI h, pencil dark, brush light) {
  return tm_new<info_box_rep> (ip, h, dark, light);
}

box
scrollbar_box (path ip, box b, bool vertical, SI span, tree t) {
  return tm_new<scrollbar_box_rep> (ip, b, vertical, span, t);
}
